﻿/*
 * KLF Headless Browser
 * Written by Kris Oye <kristianoye@gmail.com>
 * Copyright (C) 2011-2012.  All rights reserved.
 */
namespace KLF.Lib.Browser.DOM
{
    #region Using Statements

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    #endregion

    public class Attr : Node
    {
        #region Properties

        internal StringLookup _Name;
        public string Name
        {
            internal set
            {
                _Name = new StringLookup(value);
            }

            get
            {
                return _Name.Value;
            }
        }

        internal StringLookup _Value;
        public string Value
        {
            set
            {
                _Value = new StringLookup(value);
            }

            get
            {
                return _Value.Value;
            }
        }

        public bool Specified { get; internal set; }

        #endregion

        #region Constructors

        public Attr(Document owner, string _name)
            : base(owner)
        {
            Name = _name;
            Value = String.Empty;
            Specified = true;
        }

        public Attr(Attr source)
            : base(source.ownerDocument)
        {
            Name = source.name;
            Value = source.value;
            Specified = source.specified;
        }

        public override string ToString()
        {
            return String.Format("Attribute[{0} = {1}]", Name, Value);
        }

        #endregion

        #region DOM Level 1 Compliance

        public override Node cloneNode(bool deep)
        {
            return new Attr(this);
        }

        public string name { get { return Name; } }

        public override string nodeName { get { return Name; } }

        public override byte nodeType { get { return ATTRIBUTE_NODE; } }

        public override string nodeValue { get { return Value; } }

        public bool specified { get { return Specified; } }

        public string value { get { return Value; } }

        #endregion

        #region DOM Level 2 Compliance

        /// <summary>
        /// Returns the local part of the qualified name of this node.
        /// 
        /// For nodes of any type other than ELEMENT_NODE and ATTRIBUTE_NODE
        /// and nodes created with a DOM Level 1 method, such as 
        /// Document.createElement(), this is always null.
        /// </summary>
        internal StringLookup _localName;
        public override string localName
        {
            internal set
            {
                _localName = new StringLookup(value);
            }
            get
            {
                return (_localName != null ? _localName.Value : null);
            }
        }

        /// <summary>
        /// The namespace URI of this node, or null if it is unspecified 
        /// (see XML Namespaces).
        /// 
        /// This is not a computed value that is the result of a namespace 
        /// lookup based on an examination of the namespace declarations in
        /// scope. It is merely the namespace URI given at creation time.
        /// 
        /// For nodes of any type other than ELEMENT_NODE and ATTRIBUTE_NODE
        /// and nodes created with a DOM Level 1 method, such as 
        /// Document.createElement(), this is always null.
        /// 
        /// Note: Per the Namespaces in XML Specification [XML Namespaces] 
        /// an attribute does not inherit its namespace from the element it
        /// is attached to. If an attribute is not explicitly given a 
        /// namespace, it simply has no namespace.
        /// </summary>
        internal StringLookup _namespaceURI;
        public override string namespaceURI
        {
            internal set
            {
                _namespaceURI = new StringLookup(value);
            }
            get
            {
                return (_namespaceURI != null ? _namespaceURI.Value : null);
            }
        }

        /// <summary>
        /// The Element node this attribute is attached to or null if this 
        /// attribute is not in use.
        /// </summary>
        public Element ownerElement { get; internal set;  }

        /// <summary>
        /// The namespace prefix of this node, or null if it is unspecified. 
        /// When it is defined to be null, setting it has no effect, 
        /// including if the node is read-only.
        /// 
        /// Note that setting this attribute, when permitted, changes the 
        /// nodeName attribute, which holds the qualified name, as well as 
        /// the tagName and name attributes of the Element and Attr 
        /// interfaces, when applicable.
        /// 
        /// Setting the prefix to null makes it unspecified, setting it to an
        /// empty string is implementation dependent.
        /// 
        /// Note also that changing the prefix of an attribute that is known 
        /// to have a default value, does not make a new attribute with the 
        /// default value and the original prefix appear, since the 
        /// namespaceURI and localName do not change.
        /// 
        /// For nodes of any type other than ELEMENT_NODE and ATTRIBUTE_NODE 
        /// and nodes created with a DOM Level 1 method, such as createElement
        /// from the Document interface, this is always null.
        /// </summary>
        internal StringLookup _prefix;
        public override string prefix
        {
            get
            {
                return (_prefix != null ? _prefix.Value : null);
            }
            set
            {
                _prefix = new StringLookup(value);
            }
        }

        #endregion

        #region DOM Level 3 Compliance

        /// <summary>
        /// Returns whether this attribute is known to be of type ID (i.e. to
        /// contain an identifier for its owner element) or not. When it is and
        /// its value is unique, the ownerElement of this attribute can be 
        /// retrieved using the method Document.getElementById. The 
        /// implementation could use several ways to determine if an attribute 
        /// node is known to contain an identifier: 
        /// 
        /// <list>
        /// <item>If validation occurred using an XML Schema [XML Schema Part 1] 
        /// while loading the document or while invoking 
        /// Document.normalizeDocument(), the post-schema-validation infoset 
        /// contributions (PSVI contributions) values are used to determine if 
        /// this attribute is a schema-determined ID attribute using the schema-
        /// determined ID definition in [XPointer].</item>
        /// <item>If validation occurred using a DTD while loading the document 
        /// or while invoking Document.normalizeDocument(), the infoset [type 
        /// definition] value is used to determine if this attribute is a DTD-
        /// determined ID attribute using the DTD-determined ID definition in 
        /// [XPointer]. </item>
        /// <item>from the use of the methods Element.setIdAttribute(), 
        /// Element.setIdAttributeNS(), or Element.setIdAttributeNode(), i.e.
        /// it is an user-determined ID attribute; </item>
        /// </list>
        /// </summary>
        public bool isId
        {
            get
            {
                return Name.Equals("id");
            }
        }

        /// <summary>
        /// The type information associated with this attribute. While the type
        /// information contained in this attribute is guarantee to be correct 
        /// after loading the document or invoking Document.normalizeDocument(), 
        /// schemaTypeInfo may not be reliable if the node was moved. 
        /// </summary>
        public TypeInfo schemaTypeInfo
        {
            get
            {
                return new TypeInfo();
            }
        }

        #endregion
    }
}
